package aspect;

import org.springframework.beans.factory.annotation.Autowired;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.ProceedingJoinPoint;

import java.util.Date;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Arrays;

@Aspect
public class ApplicationAspect {

	@After("execution(* controllers.Application.index())")
	public void indexAfterAdvice() {
		DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
		Date date = new Date();
		System.out.println( dateFormat.format(date) + ": The index page was called");
		Logger.getInstance().loggerWrite(dateFormat.format(date) + ": The index page was loaded");
	}

	@Around("execution(* controllers.Application.joinGame())")
	public Object joinGameAfterAdvice(ProceedingJoinPoint proceedingJoinPoint) {
		DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
		Date date = new Date();
		Object value = null;
		try {
			value = proceedingJoinPoint.proceed();
		}
		catch (Throwable e) {
			e.printStackTrace();
		}
		String valueString = value.toString();
		if (valueString.contains("play.mvc.Results") ) {
			System.out.println("XXXXX : Player joined the game");
			Logger.getInstance().loggerWrite(dateFormat.format(date) + ": Player joined the game");
		}
		if (valueString.contains("SimpleResult") ) {
			System.out.println("XXXXX : Request of player was rejected");
			Logger.getInstance().loggerWrite(dateFormat.format(date) + ": Request of player was rejected");
		}
		return value;
	}

	@Around("execution(* controllers.Application.startingGame())")
	public Object startingGameAfterAdvice(ProceedingJoinPoint proceedingJoinPoint) {
		DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
		Date date = new Date();
		System.out.println( dateFormat.format(date) + ": startingGame was called");
		Logger.getInstance().loggerWrite(dateFormat.format(date) + ": startingGame was called");
		Object value = null;
		try {
			value = proceedingJoinPoint.proceed();
		}
		catch (Throwable e) {
			e.printStackTrace();
		}
		return value;
	}

	@Around("execution(* controllers.Application.gameIndex())")
	public Object gameIndexAfterAdvice(ProceedingJoinPoint proceedingJoinPoint) {
		DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
		Date date = new Date();
		System.out.println( dateFormat.format(date) + ": gameIndex");
		Logger.getInstance().loggerWrite(dateFormat.format(date) + ": gameIndex");
		Object value = null;
		try {
			value = proceedingJoinPoint.proceed();
		}
		catch (Throwable e) {
			e.printStackTrace();
		}
		return value;
	}

	@Around("execution(* controllers.Application.playedCall())")
	public Object playedCallAroundAdvice(ProceedingJoinPoint proceedingJoinPoint) {
		DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
		Date date = new Date();
		System.out.println( dateFormat.format(date) + ": ------------------- Player played CALL");
		Logger.getInstance().loggerWrite(dateFormat.format(date) + ": ------------------- Player played CALL");
		Object value = null;
		try {
			value = proceedingJoinPoint.proceed();
		}
		catch (Throwable e) {
			e.printStackTrace();
		}
		System.out.println("XXXXX : Result of playedCall: " + value);
		return value;
	}

	@Around("execution(* controllers.Application.playedRaise(*))")
	public Object playedRaiseAroundAdvice(ProceedingJoinPoint proceedingJoinPoint) {
		DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
		Date date = new Date();
		System.out.println( dateFormat.format(date) + ": ------------------- Player played RAISE");
		Logger.getInstance().loggerWrite(dateFormat.format(date) + ": ------------------- Player played RAISE");
		Object value = null;
		try {
			value = proceedingJoinPoint.proceed();
		}
		catch (Throwable e) {
			e.printStackTrace();
		}
		return value;
	}

	@Around("execution(* controllers.Application.playedBet(*))")
	public Object playedBetAroundAdvice(ProceedingJoinPoint proceedingJoinPoint) {
		DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
		Date date = new Date();
		System.out.println( dateFormat.format(date) + ": ------------------- Player played BET");
		Logger.getInstance().loggerWrite(dateFormat.format(date) + ": ------------------- Player played BET");
		Object value = null;
		try {
			value = proceedingJoinPoint.proceed();
		}
		catch (Throwable e) {
			e.printStackTrace();
		}
		return value;
	}

	@Around("execution(* controllers.Application.playedCheck())")
	public Object playedCheckAroundAdvice(ProceedingJoinPoint proceedingJoinPoint) {
		DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
		Date date = new Date();
		System.out.println( dateFormat.format(date) + ": ------------------- Player played CHECK");
		Logger.getInstance().loggerWrite(dateFormat.format(date) + ": ------------------- Player played CHECK");
		Object value = null;
		try {
			value = proceedingJoinPoint.proceed();
		}
		catch (Throwable e) {
			e.printStackTrace();
		}
		return value;
	}

	@Around("execution(* controllers.Application.playedFold())")
	public Object playedFoldAroundAdvice(ProceedingJoinPoint proceedingJoinPoint) {
		DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
		Date date = new Date();
		System.out.println( dateFormat.format(date) + ": ------------------- Player played FOLD");
		Logger.getInstance().loggerWrite(dateFormat.format(date) + ": ------------------- Player played FOLD");
		Object value = null;
		try {
			value = proceedingJoinPoint.proceed();
		}
		catch (Throwable e) {
			e.printStackTrace();
		}
		return value;
	}

	@Around("execution(* controllers.Application.playedAllIn())")
	public Object playedAllInAroundAdvice(ProceedingJoinPoint proceedingJoinPoint) {
		DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
		Date date = new Date();
		System.out.println( dateFormat.format(date) + ": ------------------- Player played ALL-IN");
		Logger.getInstance().loggerWrite(dateFormat.format(date) + ": ------------------- Player played ALL-IN");
		Object value = null;
		try {
			value = proceedingJoinPoint.proceed();
		}
		catch (Throwable e) {
			e.printStackTrace();
		}
		return value;
	}

	@Around("execution(* controllers.Application.exchangeCards(*))")
	public Object exchangeCardsAroundAdvice(ProceedingJoinPoint proceedingJoinPoint) {
		DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
		Date date = new Date();
		String string = dateFormat.format(date) + ": ------------------- Player exchanges cards.\n\t\t\t";
		if ( (Arrays.toString(proceedingJoinPoint.getArgs())).equals("[no]") ) {
			string += "He doesn't want to exchange any cards.";
		}
		else {
			string += "Want to exchange cards on indexes: " + Arrays.toString(proceedingJoinPoint.getArgs());
		}
		System.out.println( string );
		Logger.getInstance().loggerWrite( string );
		Object value = null;
		try {
			value = proceedingJoinPoint.proceed();
		}
		catch (Throwable e) {
			e.printStackTrace();
		}
		return value;
	}

//-----------------END OF CONTROLLER'S ASPECTS-----------------------------

	@Around("execution(* models.Model.cardInNumbersToCardText(*))")
	public Object cardInNumbersToCardTextAroundAdvice(ProceedingJoinPoint proceedingJoinPoint) {
		DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
		Date date = new Date();
		Object value = null;
		try {
			value = proceedingJoinPoint.proceed();
		}
		catch (Throwable e) {
			e.printStackTrace();
		}
		Logger.getInstance().loggerWrite(dateFormat.format(date) + ": cardInNumbersToCardText: " + value);
		System.out.println(dateFormat.format(date) + ": cardInNumbersToCardText: " + value);
		return value;
	}

	@Around("execution(* models.Model.setHand(*))")
	public Object setHandAroundAdvice(ProceedingJoinPoint proceedingJoinPoint) {
		DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
		Date date = new Date();
		Object value = null;
		try {
			value = proceedingJoinPoint.proceed();
		}
		catch (Throwable e) {
			e.printStackTrace();
		}
		Logger.getInstance().loggerWrite(dateFormat.format(date) + ": Message with cards from server: " + Arrays.toString(proceedingJoinPoint.getArgs()));
		System.out.println(dateFormat.format(date) + ": Message with cards from server: " + Arrays.toString(proceedingJoinPoint.getArgs()));
		return value;
	}

	@Around("execution(* models.Model.setSmallBlind(*))")
	public Object setSmallBlindAroundAdvice(ProceedingJoinPoint proceedingJoinPoint) {
		DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
		Date date = new Date();
		Object value = null;
		try {
			value = proceedingJoinPoint.proceed();
		}
		catch (Throwable e) {
			e.printStackTrace();
		}
		Logger.getInstance().loggerWrite(dateFormat.format(date) + ": Small Blind was set with value: " + Arrays.toString(proceedingJoinPoint.getArgs()) );
		System.out.println(dateFormat.format(date) + ": Small Blind was set with value: " + Arrays.toString(proceedingJoinPoint.getArgs()));
		return value;
	}

	@Around("execution(* models.Model.setBigBlind(*))")
	public Object setBigBlindAroundAdvice(ProceedingJoinPoint proceedingJoinPoint) {
		DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
		Date date = new Date();
		Object value = null;
		try {
			value = proceedingJoinPoint.proceed();
		}
		catch (Throwable e) {
			e.printStackTrace();
		}
		Logger.getInstance().loggerWrite(dateFormat.format(date) + ": Big Blind was set with value: " + Arrays.toString(proceedingJoinPoint.getArgs()) );
		System.out.println(dateFormat.format(date) + ": Big Blind was set with value: " + Arrays.toString(proceedingJoinPoint.getArgs()));
		return value;
	}

	@Around("execution(* models.Model.setParameters(*))")
	public Object setParametersAroundAdvice(ProceedingJoinPoint proceedingJoinPoint) {
		DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
		Date date = new Date();
		Object value = null;
		try {
			value = proceedingJoinPoint.proceed();
		}
		catch (Throwable e) {
			e.printStackTrace();
		}
		String msg = Arrays.toString(proceedingJoinPoint.getArgs());

		Logger.getInstance().loggerWrite(dateFormat.format(date) + ": Parameters of the player: " 
			+ "playerID = " + msg.substring(9, 10)
			+ ", playersInGame = " + msg.split(",")[1]
			+ ", bankroll = " + msg.split(",")[2]
		);
		System.out.println(dateFormat.format(date) + ": Parameters of the player: " 
			+ "playerID = " + msg.substring(9,10)
			+ ", playersInGame = " + msg.split(",")[1]
			+ ", bankroll = " + msg.split(",")[2]
		);
		return value;
	}

	@Around("execution(* models.Model.setDealer(*))")
	public Object setDealerAroundAdvice(ProceedingJoinPoint proceedingJoinPoint) {
		DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
		Date date = new Date();
		Object value = null;
		try {
			value = proceedingJoinPoint.proceed();
		}
		catch (Throwable e) {
			e.printStackTrace();
		}
		Logger.getInstance().loggerWrite(dateFormat.format(date) + ": Player with dealer button: " + Arrays.toString(proceedingJoinPoint.getArgs()) );
		System.out.println(dateFormat.format(date) + ": Player with dealer button: " + Arrays.toString(proceedingJoinPoint.getArgs()));
		return value;
	}

	@Around("execution(* models.Model.setWhoHasBigBlind(*))")
	public Object setWhoHasBigBlindAroundAdvice(ProceedingJoinPoint proceedingJoinPoint) {
		DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
		Date date = new Date();
		Object value = null;
		try {
			value = proceedingJoinPoint.proceed();
		}
		catch (Throwable e) {
			e.printStackTrace();
		}
		Logger.getInstance().loggerWrite(dateFormat.format(date) + ": The big blind has player: " + Arrays.toString(proceedingJoinPoint.getArgs()) );
		System.out.println(dateFormat.format(date) + ": The big blind has player: " + Arrays.toString(proceedingJoinPoint.getArgs()));
		return value;
	}

	@Around("execution(* models.Model.setWhoHasSmallBlind(*))")
	public Object setWhoHasSmallBlindAroundAdvice(ProceedingJoinPoint proceedingJoinPoint) {
		DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
		Date date = new Date();
		Object value = null;
		try {
			value = proceedingJoinPoint.proceed();
		}
		catch (Throwable e) {
			e.printStackTrace();
		}
		Logger.getInstance().loggerWrite(dateFormat.format(date) + ": The small blind has player: " + Arrays.toString(proceedingJoinPoint.getArgs()) );
		System.out.println(dateFormat.format(date) + ": The small blind has player: " + Arrays.toString(proceedingJoinPoint.getArgs()));
		return value;
	}

	@Around("execution(* models.Model.setPlayerBankrollNow(*))")
	public Object setPlayerBankrollNowAroundAdvice(ProceedingJoinPoint proceedingJoinPoint) {
		DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
		Date date = new Date();
		Object value = null;
		try {
			value = proceedingJoinPoint.proceed();
		}
		catch (Throwable e) {
			e.printStackTrace();
		}
		Logger.getInstance().loggerWrite(dateFormat.format(date) + ": Player has " + Arrays.toString(proceedingJoinPoint.getArgs()) + " in bankroll now." );
		System.out.println(dateFormat.format(date) + ": setPlayerBankrollNow: " + Arrays.toString(proceedingJoinPoint.getArgs()));
		return value;
	}

	@Around("execution(* models.Model.setMaxBetNow(*))")
	public Object setMaxBetNowAroundAdvice(ProceedingJoinPoint proceedingJoinPoint) {
		DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
		Date date = new Date();
		Object value = null;
		try {
			value = proceedingJoinPoint.proceed();
		}
		catch (Throwable e) {
			e.printStackTrace();
		}
		Logger.getInstance().loggerWrite(dateFormat.format(date) + ": Max bet was set: " + Arrays.toString(proceedingJoinPoint.getArgs()) );
		System.out.println(dateFormat.format(date) + ": Max bet was set: " + Arrays.toString(proceedingJoinPoint.getArgs()));
		return value;
	}

	@Around("execution(* models.Model.setPlayerBetNow(*))")
	public Object setPlayerBetNowAroundAdvice(ProceedingJoinPoint proceedingJoinPoint) {
		DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
		Date date = new Date();
		Object value = null;
		try {
			value = proceedingJoinPoint.proceed();
		}
		catch (Throwable e) {
			e.printStackTrace();
		}
		Logger.getInstance().loggerWrite(dateFormat.format(date) + ": Player bet was set: " + Arrays.toString(proceedingJoinPoint.getArgs()) );
		System.out.println(dateFormat.format(date) + ": Player bet was set: " + Arrays.toString(proceedingJoinPoint.getArgs()));
		return value;
	}

	@Around("execution(* models.Model.setIDOfPlayerWhoPlayed(*))")
	public Object setIDOfPlayerWhoPlayedAroundAdvice(ProceedingJoinPoint proceedingJoinPoint) {
		DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
		Date date = new Date();
		Object value = null;
		try {
			value = proceedingJoinPoint.proceed();
		}
		catch (Throwable e) {
			e.printStackTrace();
		}
		Logger.getInstance().loggerWrite(dateFormat.format(date) + ": Player ID who play: " + Arrays.toString(proceedingJoinPoint.getArgs()) );
		System.out.println(dateFormat.format(date) + ": Player ID who play: " + Arrays.toString(proceedingJoinPoint.getArgs()));
		return value;
	}

	@Around("execution(* models.Model.setBetValueOfPlayerWhoPlayed(*))")
	public Object setBetValueOfPlayerWhoPlayedAroundAdvice(ProceedingJoinPoint proceedingJoinPoint) {
		DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
		Date date = new Date();
		Object value = null;
		try {
			value = proceedingJoinPoint.proceed();
		}
		catch (Throwable e) {
			e.printStackTrace();
		}
		Logger.getInstance().loggerWrite(dateFormat.format(date) + ": Player has " + Arrays.toString(proceedingJoinPoint.getArgs()) + " in bankroll now.");
		System.out.println(dateFormat.format(date) + ": setBetValueOfPlayerWhoPlayed: " + Arrays.toString(proceedingJoinPoint.getArgs()));
		return value;
	}

	@Around("execution(* models.Model.setPlayerIDWhoExchanged(*))")
	public Object setPlayerIDWhoExchangedAroundAdvice(ProceedingJoinPoint proceedingJoinPoint) {
		DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
		Date date = new Date();
		Object value = null;
		try {
			value = proceedingJoinPoint.proceed();
		}
		catch (Throwable e) {
			e.printStackTrace();
		}
		Logger.getInstance().loggerWrite(dateFormat.format(date) + ": Exchange cards. Now is playing player " + (Arrays.toString(proceedingJoinPoint.getArgs())).substring(11,12) );
		System.out.println(dateFormat.format(date) + ": Exchange cards. Now is playing player " + Arrays.toString(proceedingJoinPoint.getArgs()));
		return value;
	}

	@Around("execution(* models.Model.setNrOfExchangedCards(*))")
	public Object setNrOfExchangedCardsAroundAdvice(ProceedingJoinPoint proceedingJoinPoint) {
		DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
		Date date = new Date();
		Object value = null;
		try {
			value = proceedingJoinPoint.proceed();
		}
		catch (Throwable e) {
			e.printStackTrace();
		}
		Logger.getInstance().loggerWrite(dateFormat.format(date) + ": exchange : " + (Arrays.toString(proceedingJoinPoint.getArgs())).substring(9,10) + " cards." );
		System.out.println(dateFormat.format(date) + ": setNrOfExchangedCards: " + Arrays.toString(proceedingJoinPoint.getArgs()));
		return value;
	}

	@Around("execution(* models.Model.setWinnerID(*))")
	public Object setWinnerIDAroundAdvice(ProceedingJoinPoint proceedingJoinPoint) {
		DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
		Date date = new Date();
		Object value = null;
		try {
			value = proceedingJoinPoint.proceed();
		}
		catch (Throwable e) {
			e.printStackTrace();
		}
		Logger.getInstance().loggerWrite(dateFormat.format(date) + ": ID of the winner: " + (Arrays.toString(proceedingJoinPoint.getArgs())).substring(12,13) );
		System.out.println(dateFormat.format(date) + ": setWinnerID: " + Arrays.toString(proceedingJoinPoint.getArgs()));
		return value;
	}

	@Around("execution(* models.Model.setWinningAmount(*))")
	public Object setWinningAmountAroundAdvice(ProceedingJoinPoint proceedingJoinPoint) {
		DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
		Date date = new Date();
		Object value = null;
		try {
			value = proceedingJoinPoint.proceed();
		}
		catch (Throwable e) {
			e.printStackTrace();
		}
		Logger.getInstance().loggerWrite(dateFormat.format(date) + ": The winner wins " + (Arrays.toString(proceedingJoinPoint.getArgs())).split(",")[2] );
		System.out.println(dateFormat.format(date) + ": setWinnerID: " + Arrays.toString(proceedingJoinPoint.getArgs()));
		return value;
	}


}
